﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;


namespace cimdict
{
    public class CIMGUIComponents
    {
        public ToolStripProgressBar progressBar;
        public ToolStripStatusLabel statusLabel;
        public TreeView classTreeView;
        //public TreeView propTreeView;
        public TreeView inheritTreeView;
        public TreeView fullPropTreeView;
        public Form mainForm;

        public TextBox className;
        public TextBox classBaseName;
        public TextBox classVersion;
        public TextBox classFilePath;
        public RichTextBox classDescription;
        public TextBox propName;
        public TextBox propParam;
        public TextBox propDefination;
        public RichTextBox propDescription;

        public string selectedClassName;
        public string selectedPropName;

    }

    public class CIMInterface : CIMRepo
    {
        protected CIMInterface()
        { 
        
        }

        public static CIMGUIComponents GUI = new CIMGUIComponents();


        //Step init with progress bar
        public static void initUI(  )
        {
            GUI.statusLabel.Text = "Retrieving all mof files in target directory ......";
            GUI.mainForm.Refresh();
            CIMRepo.MOFFiles = CIMRepo.getAllMOF("");
            GUI.progressBar.Maximum = CIMRepo.MOFFiles.Count;
            GUI.progressBar.Minimum = 0;
            GUI.progressBar.Value = 0;

            //Read all MOF files
            GUI.statusLabel.Text = "Reading all mof files ......";
            GUI.mainForm.Refresh();
            int i = 0;
            foreach (string filename in CIMRepo.MOFFiles)
            {
                Console.WriteLine("# " + i++);
                CIMClass cim = new CIMClass(filename);
                CIMRepo.addClass(cim);
                GUI.progressBar.Value++;
            }
            CIMRepo.CIMClasses.Sort(delegate(CIMClass c1, CIMClass c2) { return c1.name.CompareTo(c2.name); });

            //Link base class
            GUI.progressBar.Maximum = CIMRepo.CIMClasses.Count;
            GUI.progressBar.Minimum = 0;
            GUI.progressBar.Value = 0;
            GUI.statusLabel.Text = "Linking class ......";
            GUI.mainForm.Refresh();
            foreach (CIMClass cim in CIMRepo.CIMClasses)
            {
                if (cim.baseName != "")
                {
                    foreach (CIMClass cimBase in CIMRepo.CIMClasses)
                    {
                        if ( cim.inheritFrom(cimBase) ) 
                        {
                            cim.baseClass = cimBase;
                            break;
                        }
                    }
                }
                GUI.progressBar.Value++;
            }

            GUI.statusLabel.Text = "OK";
            GUI.mainForm.Refresh();
        }

        public static void hierarchyView()
        {
            GUI.classTreeView.Nodes.Clear();

            //Make class tree view
            GUI.statusLabel.Text = "Building class tree view ......";
            GUI.mainForm.Refresh();
            GUI.progressBar.Maximum = CIMRepo.CIMClasses.Count;
            GUI.progressBar.Minimum = 0;
            GUI.progressBar.Value = 0;

            Collection<CIMClass> handled = new Collection<CIMClass>();
            int addCount = 0;
            while (handled.Count < CIMRepo.CIMClasses.Count)
            {
                addCount = 0;
                foreach (CIMClass cim in CIMRepo.CIMClasses)
                {
                    if (handled.IndexOf(cim) >= 0)
                    {
                        continue;
                    }
                    if (tryAddNode(GUI.classTreeView.Nodes, cim))
                    {
                        addCount++;
                        handled.Add(cim);
                    }
                }
                GUI.progressBar.Value += addCount;
                if (addCount == 0) break;
            }

            foreach (CIMClass cim in CIMRepo.CIMClasses)
            {
                if (handled.IndexOf(cim) < 0)
                {
                    //Break here to see what we missed
                }
            }

            GUI.statusLabel.Text = "OK";
            GUI.mainForm.Refresh();
        }

        public static void plainView()
        {
            GUI.classTreeView.Nodes.Clear();

            GUI.statusLabel.Text = "Building class plan view ......";
            GUI.mainForm.Refresh();
            GUI.progressBar.Maximum = CIMRepo.CIMClasses.Count;
            GUI.progressBar.Minimum = 0;
            GUI.progressBar.Value = 0;

            foreach (CIMClass cim in CIMRepo.CIMClasses)
            {
                if (cim.name != "")
                {
                    CIMInterface.addClassNode(GUI.classTreeView.Nodes, cim);
                }
                GUI.progressBar.Value++;
            }

            GUI.statusLabel.Text = "OK";
            GUI.mainForm.Refresh();
        }

        public static void filterView( string[] keys )
        {
            GUI.classTreeView.Nodes.Clear();

            GUI.statusLabel.Text = "Building class filter view ......";
            GUI.mainForm.Refresh();
            GUI.progressBar.Maximum = CIMRepo.CIMClasses.Count;
            GUI.progressBar.Minimum = 0;
            GUI.progressBar.Value = 0;

            bool unmatchedKey;
            foreach (CIMClass cim in CIMRepo.CIMClasses)
            {
                unmatchedKey = false;
                foreach (string key in keys)
                {
                    if (key == null || key == "")
                    {
                        //No a valid key
                        continue;
                    }
                    if (! cim.contains(key))
                    {
                        unmatchedKey = true;
                        break;
                    }
                }
                if (!unmatchedKey)
                {
                    CIMInterface.addClassNode(GUI.classTreeView.Nodes, cim);
                }
                GUI.progressBar.Value++;
            }

            GUI.statusLabel.Text = "OK";
            GUI.mainForm.Refresh();
        }


        //Add cim node to the node collections or the sub-collection of each nod
        //By the inheritance
        private static bool tryAddNode(TreeNodeCollection tnc, CIMClass cim)
        {
            if (cim.name == "")
            {
                return false;
            }
            if (cim.baseName == "")
            {
                CIMInterface.addClassNode(tnc, cim);
                return true;
            }

            foreach (TreeNode tn in tnc)
            {
                if ( cim.inheritFrom(tn.Name) )
                {
                    CIMInterface.addClassNode(tn.Nodes, cim);
                    return true;
                }
                if (tryAddNode(tn.Nodes, cim))
                {
                    return true;
                }
            }
            return false;
        }

        //Just add node directly
        public static void addClassNode(TreeNodeCollection tnc, CIMClass cim)
        {
            TreeNode tn = new TreeNode();
            tn.Name = cim.nameLower;
            tn.Text = cim.name;
            tnc.Add(tn);
        }

        //Just add node directly
        public static void addPropNode(TreeNodeCollection tnc, CIMProp prop, bool isInherited)
        {
            TreeNode tn = new TreeNode();
            tn.Name = prop.nameLower;
            if (isInherited)
            {
                tn.Text = prop.name + " (Inherited)";
            }
            else
            {
                tn.Text = prop.name;
            }
            tnc.Add(tn);
        }

        public static void selectClass(string selectedClassName)
        {
            if (selectedClassName == "") return;
            CIMClass cim = CIMRepo.getClass(selectedClassName);
            if (cim != null)
            {
                //Set class Tree View
                foreach ( TreeNode tn in GUI.classTreeView.Nodes )
                {
                    if (cim.equalTo(tn.Name))
                    {
                        GUI.classTreeView.SelectedNode = tn;
                    }
                }
                GUI.selectedClassName = selectedClassName;

                //Set Class display
                GUI.className.Text = cim.name;
                GUI.classBaseName.Text = cim.baseName;
                GUI.classVersion.Text = cim.ver;
                GUI.classFilePath.Text = cim.fileName;
                GUI.classDescription.Text = cim.desc;

                //Clear Class prop display
                GUI.propName.Text = "";
                GUI.propParam.Text = "";
                GUI.propDefination.Text = "";
                GUI.propDescription.Text = "";

                //Set all tree views
                //setPropTreeView(cim);

                setInheritTreeView(cim);

                setFullPropTreeView(cim);
            }
        }

        protected static void setFullPropTreeView(CIMClass cim)
        {
            //Set Full Prop Tree View
            GUI.fullPropTreeView.Nodes.Clear();

            CIMClass pcim = cim;
            while (pcim != null)
            {
                TreeNode tn = new TreeNode();
                tn.Name = pcim.nameLower;
                tn.Text = pcim.name;
                GUI.fullPropTreeView.Nodes.Add(tn);

                foreach (CIMProp prop in pcim.props)
                {
                    //Chec if the prop was inheritaed
                    bool isInherited = false;
                    CIMClass tmpcim = pcim.baseClass;
                    while (tmpcim != null)
                    {
                        foreach (CIMProp pp in tmpcim.props)
                        {
                            if (pp.equalTo(prop))
                            {
                                isInherited = true;
                                break;
                            }
                        }
                        if (isInherited) break;
                        tmpcim = tmpcim.baseClass;
                    }

                    addPropNode(tn.Nodes, prop, isInherited);
                }
                pcim = pcim.baseClass;
            }

            GUI.fullPropTreeView.ExpandAll();
            if (GUI.fullPropTreeView.Nodes.Count > 0)
            {
                GUI.fullPropTreeView.SelectedNode = GUI.fullPropTreeView.Nodes[0];
            }
        }

        /*
        protected static void setPropTreeView(CIMClass cim)
        {
            //Set Class Prop Tree View
            GUI.propTreeView.Nodes.Clear();

            TreeNode propRootNode = new TreeNode();
            propRootNode.Name = cim.nameLower;
            propRootNode.Text = cim.name;
            GUI.propTreeView.Nodes.Add(propRootNode);
            foreach (CIMProp prop in cim.props)
            {
                addPropNode(propRootNode.Nodes, prop);
            }

            GUI.propTreeView.ExpandAll();
        }*/

        protected static void setInheritTreeView(CIMClass cim)
        {
            //Set Inherit Tree View
            //Current class exist in inherit view, just keep it
            if (searchClassNode(GUI.inheritTreeView.Nodes, cim) != null)
            {
                return;
            }
            
            //Need build new inherit tree view
            GUI.inheritTreeView.Nodes.Clear();
            CIMClass pcim = cim;
            TreeNode inode = new TreeNode();
            inode.Name = pcim.nameLower;
            inode.Text = pcim.name;

            pcim = pcim.baseClass;
            while (pcim != null)
            {
                TreeNode tmpNode = new TreeNode();
                tmpNode.Name = pcim.nameLower;
                tmpNode.Text = pcim.name;
                tmpNode.Nodes.Add(inode);

                inode = tmpNode;
                pcim = pcim.baseClass;
            }
            GUI.inheritTreeView.Nodes.Add(inode);
            GUI.inheritTreeView.ExpandAll();
        }

        protected static TreeNode searchClassNode( TreeNodeCollection tnc, CIMClass cim )
        {
            if (tnc.Count == 0) return null;

            foreach (TreeNode tn in tnc)
            {
                if (cim.equalTo(tn.Name))
                {
                    return tn;
                }
                TreeNode subtn = searchClassNode(tn.Nodes, cim);
                if (subtn != null)
                {
                    return subtn;
                }
            }
            return null;
        }


        public static void selectProp(string propName)
        {
            string className = GUI.selectedClassName;

            if (className == "" || propName == "") return;
            CIMClass cim = CIMRepo.getClass(className);
            if (cim != null)
            {
                CIMProp prop = cim.getProp(propName);
                if (prop != null)
                {
                    GUI.selectedPropName = propName;

                    GUI.propName.Text = prop.name;
                    GUI.propParam.Text = prop.param;
                    GUI.propDescription.Text = prop.desc;
                    if (prop.isFunc)
                    {
                        GUI.propDefination.Text = prop.fullName + "(...)";
                    }
                    else
                    {
                        GUI.propDefination.Text = prop.fullName;
                    }
                }
            }
        }

        public static void selectFullProp()
        {
            TreeNode snode = GUI.fullPropTreeView.SelectedNode;
            if ( snode == null) return;
            //snode should be the leaf node that represents prop
            if (snode.Nodes.Count > 0 || snode.Parent == null) 
            {
                return;
            }

            string propName = snode.Name;
            string className = snode.Parent.Name;
            if (propName == null || propName == "" || className == null || className == "") return;

            CIMClass cim = CIMRepo.getClass(className);
            if (cim != null)
            {
                CIMProp prop = cim.getProp(propName);
                if (prop != null)
                {
                    GUI.selectedPropName = propName;

                    GUI.propName.Text = prop.name;
                    GUI.propParam.Text = prop.param;
                    GUI.propDescription.Text = prop.desc;
                    if (prop.isFunc)
                    {
                        GUI.propDefination.Text = prop.fullName + "(...)";
                    }
                    else
                    {
                        GUI.propDefination.Text = prop.fullName;
                    }
                }
            }
        }

    }
}
